package gagak.framework.web.core;

import gagak.framework.web.adapter.HandlerAdapter;
import gagak.framework.web.annonation.RequestMapping;
import gagak.framework.web.context.MvcApplicationContext;
import gagak.framework.web.context.MvcContextApplicationHolder;
import gagak.framework.web.exception.HxWebException;
import gagak.framework.web.handler.HandlerExecutionChain;
import gagak.framework.web.handler.HandlerMapping;
import gagak.framework.web.reflect.AnnotationAttributes;
import gagak.framework.web.reflect.AnnotationUtils;
import gagak.framework.web.utils.ObjectUtils;
import gagak.framework.web.view.View;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;


/*
 * @program: ce
 * @description: 前端处理器
 * @author: houhong
 * @create: 2022-12-01 16:57
 */
public final class DispatcherServlet extends FrameworkServlet {


    private static Logger logger = LoggerFactory.getLogger(com.g5.framework.web.DispatcherServlet.class);
    //初始化开关
    public static volatile Boolean INIT_SWATCH = Boolean.TRUE;


    /*
     * 容器原子
     */
    private static volatile AtomicReference<MvcApplicationContext> mvcApplicationContextAtomicRef = new AtomicReference<MvcApplicationContext>();

    private static MvcApplicationContext mvcApplicationContext;

    /*
     * 适配器
     */
    private static volatile List<HandlerAdapter> handlerAdapters = new CopyOnWriteArrayList<HandlerAdapter>();
    /*
     * 映射器
     */
    private static volatile List<HandlerMapping> handlerMappings = new CopyOnWriteArrayList<HandlerMapping>();
    /*
     * 视图解析器
     */
    private static volatile List<View> viewResovers = new CopyOnWriteArrayList<View>();

    @Override
    public void doService(HttpServletRequest request, HttpServletResponse response) {
        //初始化信息
        initMvcContext();

        HandlerExecutionChain handlerExecutionChain = null;
        //定义是不是文件下载器
        boolean multpartRequestParsed = false;

        //  upload /dowmload
        Object result = null;
        multpartRequestParsed = checkMultPart(request);

        //获取handler
        handlerExecutionChain = getHandler(request);

        String requestURI = request.getRequestURI();
        if (handlerExecutionChain == null) {
            logger.error("【mvc-framework】not found handler，please check the url-mapping:{}", requestURI);
            return;
        }

        //干活的
        HandlerAdapter adapter = getAdapter(handlerExecutionChain.getHandler());

        //做文件上下传
        if (multpartRequestParsed) {

        } else {
            //普通的处理
            result = adapter.handle(request, response, handlerExecutionChain.getHandler());
        }
        //这里只是做返回处理
        processDispatchResult(request, response, result);

    }

    /*
     * 返回结果
     */
    protected void processDispatchResult(HttpServletRequest request, HttpServletResponse response, Object result) {

        View view = null;

        String contentType = request.getContentType();
        for (View viewResover : viewResovers) {

            if (viewResover.support(contentType)) {
                view = viewResover;
                break;
            }
        }

        if (ObjectUtils.isEmpty(view)) {
            logger.error("【mvc-framework】not find the apater viewsovler,please check the " +
                    " viewSolver is adaptied to the contentType:【" + contentType + "】");
            throw new HxWebException("");

        }
        try {
            view.render(result, request, response);
        } catch (Throwable e) {
            e.printStackTrace();
            //// TODO: 2022/12/1
        } finally {
        }
    }

    protected void initMvcContext() {

        for (; ; ) {

            if (!INIT_SWATCH) {
                return;
            }
            if (mvcApplicationContextAtomicRef.compareAndSet(null, MvcContextApplicationHolder.getMvcApplicationContext())) {

                mvcApplicationContext = mvcApplicationContextAtomicRef.get();
                // 初始化适配器
                handlerAdapters = mvcApplicationContext.getHandlerAdapters();
                // 初始化handlerMapping
                handlerMappings = mvcApplicationContext.getHandlerMappings();
                //初始化视图解析器
                viewResovers = mvcApplicationContext.getViewResolvers();
                //初始化完毕，其他线程退出。  -- 这里可以考虑使用阻塞唤醒，让其他线程阻塞，不需要自旋。
                INIT_SWATCH = Boolean.FALSE;
            } else {
                // 阻塞
                LockSupport.parkNanos(50L);
            }
        }


    }

    /*
     * 根据ahandler  获取handler
     */
    protected HandlerAdapter getAdapter(Object handler) {

        for (HandlerAdapter handlerAdapter : handlerAdapters) {

            if (handlerAdapter.support(handler)) {
                return handlerAdapter;
            }
        }

        return null;
    }


    protected HandlerExecutionChain getHandler(HttpServletRequest request) {

        // TODO: 2022/11/23  获取handler
        String requestURI = request.getRequestURI();
        logger.info("【mvc-framework】is handling on request-url:{}", requestURI);
        try {
            for (HandlerMapping handlerMapping : handlerMappings) {
                HandlerExecutionChain handler = handlerMapping.getHandler(request);
                return handler;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }

        return null;
    }

    protected void dealResult(HttpServletResponse response, Object result) {


    }


    /*
     * 是否是文件上下传
     */
    private boolean checkMultPart(HttpServletRequest request) {

        return false;
    }


    public static void main(String[] args) throws Exception {


        RequestMapping annotation = com.g5.framework.web.DispatcherServlet.class.getAnnotation(RequestMapping.class);

        AnnotationAttributes annotationAttributes = (AnnotationAttributes) AnnotationUtils.getAnnotationAttributes(annotation);

        System.out.println(1);
    }
}